using System;
using System.Threading;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT;
using mocom.IOBus;

namespace IOBusAPiTest
{
    public class Program
    {
        // signal cycle complete, data available
        public static void OnCycleComplete(uint cycle, uint error, DateTime time)
        {
            Debug.Print("CYCLE #" + cycle);

            if (cycle == 0x00)
            {
                // reset outputs on HAGPSIO 0
                IOBusApi.WriteInt(0, 0, 0x00);
            }
            else if (cycle == 0x10)
            {
                // set output 0 on HAGPSIO 0
                IOBusApi.WriteInt(0, 0, 0x01);
            }
            else if (cycle == 0x20)
            {
                // set outputs 0,1 on HAGPSIO 0
                IOBusApi.WriteInt(0, 0, 0x03);
            }
            else if (cycle == 0x30)
            {
                // set outputs 0,1,2 on HAGPSIO 0
                IOBusApi.WriteInt(0, 0, 0x07);
            }

            if (error != 0)
            {
                Debug.Print("Error: " + IOBusApi.GetErrorString((int) error));
            }
            for (int node = 0; node < 4; node++)
            {
                for (int objects = 0; objects < IOBusApi.GetNumberOfObjects(node); objects++)
                {
                    string inout = IOBusApi.GetClassName(node, objects);
 
                    switch (IOBusApi.GetType(node, objects))
                    {
                        case IOBusApi.OBJ_IS_DIGITAL:
                            UInt32 ioval = (UInt32) IOBusApi.ReadInt(node, objects);
                            string iostring = "";
                            for (int io = 0; io < 32; io++) 
                            {
                                if ((ioval & (1 << io)) == 0) 
                                {
                                    iostring +=  "_";
                                }
                                else
	                            {
                                    iostring +=  "I";
	                            }
                            }
                            Debug.Print("DI " + inout + ": " + iostring);
                            break;

                        case IOBusApi.OBJ_IS_ANALOG:
                            float adval=IOBusApi.ReadFloat(node, objects);
                            Debug.Print("AN " + inout + ": " + adval.ToString() + "[" + IOBusApi.GetPhysicalUnit(node, objects) + "]");
                            break;

                        case IOBusApi.OBJ_IS_COUNTER:
                            UInt32 counter = (UInt32) IOBusApi.ReadInt(node, objects);
                            Debug.Print("CO " + inout + ": " + counter);
                            break;                        

                        default:
                            Debug.Print("OBJECT TYPE UNKNOWN NODE=" + node + " OBJECT=" + objects.ToString());
                            break; 
                    }
                }
            }
            // we processed thisone, ready for next
            IOBusApi.AckDataCallback();
        }

        // signal unexpected, non-sequential errors
        public static void OnError(uint node, uint error, DateTime time)
        {
            Debug.Print("ERROR CYCLE #" + node.ToString() + " " + IOBusApi.GetErrorString((int)error));
            // we processed thisone, ready for next
            IOBusApi.AckErrorCallback();
        }
        
        // main
        public static void Main()
        {
            // assign data complete handler
            NativeEventDispatcher dataevent = new NativeEventDispatcher(IOBusApi.dataCallback,0);
            NativeEventHandler eventHandler = new NativeEventHandler(OnCycleComplete);
            dataevent.OnInterrupt += eventHandler;

            // assign error handler
            NativeEventDispatcher errorevent = new NativeEventDispatcher(IOBusApi.errorCallback, 0);
            NativeEventHandler errorHandler = new NativeEventHandler(OnError);
            errorevent.OnInterrupt += errorHandler;

            // enable bus
            IOBusApi.Enable(1);

            try
            {
                while (!IOBusApi.IsEnabled())
                {
                    Thread.Sleep(1000);
                }
            }
            catch
            {
                Debug.Print("ERROR: CAN'T ENABLE IOBUS, HARDWARE ERROR");
                return;
            }

            Debug.Print(" *** Started ***");

            // preset COUNTER 0 with 10000
            IOBusApi.WriteInt(0, 2, 10000);
            
            while (true)
            {
                Thread.Sleep(1000);
            }
        }
    }
}
